package com.fdb.efp.nls.service.impl.signature;

import com.alibaba.fastjson.JSONObject;
import com.fdb.basic.framework.core.base.FrameworkService;
import com.fdb.basic.framework.core.util.UUIDUtil;
import com.fdb.efp.console.common.psd.PsdConstantSet;
import com.fdb.efp.nls.service.facade.SCfgParamService;
import com.fdb.efp.console.service.vo.SCfgParamVO;
import com.fdb.efp.nls.common.ImageBizConstant;
import com.fdb.efp.nls.common.UploadRtMsg;
import com.fdb.efp.nls.common.bo.UpLoadFileVO;
import com.fdb.efp.nls.service.dao.CertUploadRecordDAO;
import com.fdb.efp.nls.service.dao.ImageBizDetailDao;
import com.fdb.efp.nls.service.dao.ImageBizInfoDao;
import com.fdb.efp.nls.service.domain.CertUploadRecord;
import com.fdb.efp.nls.service.domain.ImageBizDetail;
import com.fdb.efp.nls.service.domain.ImageBizInfo;
import com.fdb.efp.nls.service.facade.UpLoadFileService;
import com.fdb.efp.nls.service.facade.signature.PsdCertUploadService;
import com.fdb.efp.nls.service.facade.NlsApplyInfoService;
import com.fdb.efp.nls.service.facade.sx.NlsCreditInfoService;
import com.fdb.efp.nls.service.vo.NlsApplyInfoVO;
import com.fdb.efp.nls.service.vo.sx.NlsCreditInfoVO;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * 普税贷文件上传服务（授信）
 *
 * @author xiaojnhui
 */
@Service("psdCertUploadService")
public class PsdCertUploadServiceImpl implements PsdCertUploadService, FrameworkService {

    private static Logger logger = LoggerFactory.getLogger(PsdCertUploadServiceImpl.class);

    @Autowired
    private CertUploadRecordDAO certUploadRecordDAO;

    @Autowired
    @Qualifier("upLoadFileService")
    private UpLoadFileService upLoadFileService;

    @Autowired
    @Qualifier("nlsCreditInfoService")
    private NlsCreditInfoService nlsCreditInfoService;

    @Autowired
    @Qualifier("nlsApplyInfoService")
    private NlsApplyInfoService nlsApplyInfoService;

    @Autowired
    private ImageBizDetailDao imageBizDetailDao;

    @Autowired
    private ImageBizInfoDao imageBizInfoDao;

    @Autowired
    @Qualifier("sCfgParamService")
    private SCfgParamService sCfgParamService;

    /**
     * 切割符号
     */
    private String splitStr = "_";

    @Override
    public Boolean decompression(String zipFileUrl, String descPath) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("身份证文件解压");
        logger.info("开始解压身份证文件---待解压文件路径：", zipFileUrl, "---存放解压后文件路径：", descPath);
        try {
            File srcFile = new File(zipFileUrl);
            if (!srcFile.exists()) {
                throw new RuntimeException("获取到的待解压的文件不存在,待解压文件路径为：" + zipFileUrl);
            }
            logger.info("待解压文件大小：", srcFile.length());
            File descFile = new File(descPath);
            if (!descFile.exists()) {
                FileUtils.forceMkdir(descFile);
            }
            ZipFile zipFile = new ZipFile(srcFile);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();
                String pathname = descPath + zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    FileUtils.forceMkdir(new File(pathname));
                } else {
                    File targetFile = new File(pathname);
                    if (!targetFile.getParentFile().exists()) {
                        FileUtils.forceMkdir(targetFile.getParentFile());
                    }
                    if (targetFile.exists()) {
                        targetFile.delete();
                    }
                    targetFile.createNewFile();
                    //将压缩文件内容写入到这个文件中
                    InputStream inputStream = zipFile.getInputStream(zipEntry);
                    FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = inputStream.read(buf)) != -1) {
                        fileOutputStream.write(buf, 0, len);
                    }
                    closeStream(inputStream, fileOutputStream);
                    //插入一条日志到数据库 以便上传定时器进行上传操作
                    if (certUploadRecordDAO.countByFileUrl(targetFile.getAbsolutePath()) > 0) {
                        //已经存在这个文件了 那么将不做处理
                        continue;
                    }
                    CertUploadRecord record = new CertUploadRecord();
                    record.setId(UUIDUtil.getUUID());
                    record.setPrdId(PsdConstantSet.prdId);
                    record.setCreateTime(new Date());
                    record.setFileUrl(targetFile.getAbsolutePath());
                    record.setUpSta(0);
                    record.setUpNum(0);
                    certUploadRecordDAO.insert(record);
                    //插入一条日志数据到影像明细表
                    insertImageBizDetail(targetFile);
                    insertImageBizInfo(targetFile);
                    continue;
                }
            }
            stopWatch.stop();
            logger.info("结束解压身份证文件---待解压文件路径：", zipFileUrl, "---存放解压后文件路径：", descPath, "----总共耗时为：", stopWatch.shortSummary());
            //删除文件
            if (srcFile.exists()) {
                srcFile.delete();
            }
            return Boolean.TRUE;
        } catch (IOException e) {
            logger.error("解压身份证文件发生异常：", e);
            return Boolean.FALSE;
        }
    }

    @Override
    public Boolean upLoad() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("身份证文件上传定时任务");
        logger.info("普税贷身份证信息上传定时器开始执行");
        //获取配置信息
        final int[] handleNumArr = getHandleNumArr();
        //取未成功上传的并且上传次数小于等于3的记录进行处理
        logger.info("普税贷身份证信息上传定时器:最大处理数量=" + handleNumArr[0] + "-------重试次数=" + handleNumArr[1]);
        List<CertUploadRecord> certUploadRecords = certUploadRecordDAO.selectNeedUploadList(handleNumArr[0], handleNumArr[1], PsdConstantSet.prdId);
        if (certUploadRecords == null || certUploadRecords.isEmpty()) {
            logger.info("获取到需要上传的身份证记录为空");
            return Boolean.TRUE;
        }
        logger.info("开始循环处理身份证文件上传,总共需要处理的记录数量为：{}", certUploadRecords.size());
        for (CertUploadRecord certUploadRecord : certUploadRecords) {
            //一条条信息上传
            certUploadRecord.setUpNum(certUploadRecord.getUpNum() + 1);
            certUploadRecord.setUpTime(new Date());
            try {
                //判断文件是否存在 不存在则保存日志并且跳过
                if (!new File(certUploadRecord.getFileUrl()).exists()) {
                    throw new RuntimeException("根据文件路径获取到的文件不存在,文件路径为：" + certUploadRecord.getFileUrl());
                }
                //获取文件名
                String certBaseName = FilenameUtils.getBaseName(certUploadRecord.getFileUrl());
                //文件名切割 流水号 文件标志  或者 流水号  tm 文件标志
                String[] certBaseNameArr = certBaseName.split(splitStr);
                final PsdImgInfo imgInfo = getImgInfo(certBaseNameArr[1]);
                //根据文件名获取相应的授信或者用信数据
                NlsStamInfo nlsStamInfo = getNlsStamInfo(certBaseNameArr[0], imgInfo);
                if (Objects.isNull(nlsStamInfo)) {
                    throw new RuntimeException("根据流水号：" + certBaseNameArr[0] + "获取到的申请记录为空.文件类型为:" + certBaseNameArr[1]);
                }
                //根据授信记录获取成功的上传记录，如果获取得到 则后面的上传操作使用获取到的批次号进行文件追加
                UpLoadFileVO upLoadFileVO = upLoadFileService.queryFirstUpLoadFileByReq(certBaseNameArr[0], "SUCCESS");
                String startDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                if (Objects.isNull(upLoadFileVO)) {
                    //做文件上传
                    String retMsg = UploadFileUtils.uploadOneFile(nlsStamInfo, imgInfo,
                            certUploadRecord.getFileUrl(),
                            startDate,
                            startDate
                    );
                    //解析返回的报文
                    UploadRtMsg uploadRtMsg = UploadFileUtils.explainRetMsg(retMsg);
                    if (uploadRtMsg.isSuccess()) {
                        UpLoadFileVO saveUploadFileVO = getUpLoadFileVO(certUploadRecord, nlsStamInfo, startDate, uploadRtMsg, imgInfo);
                        saveUploadFileVO.setState("SUCCESS");
                        upLoadFileService.insertUpLoadFile(saveUploadFileVO);
                        //删除文件
                        deleteFile(certUploadRecord);
                    }
                    certUploadRecord.setUpSta(uploadRtMsg.isSuccess() ? 1 : 2);
                    certUploadRecord.setUpRetMsg(JSONObject.toJSONString(uploadRtMsg));
                    certUploadRecordDAO.updateByPrimaryKey(certUploadRecord);
                } else {
                    //做文件追加
                    String retMsg = UploadFileUtils.addOneFile(nlsStamInfo, imgInfo,
                            startDate, certUploadRecord.getFileUrl(),
                            upLoadFileVO.getStartDate(),
                            upLoadFileVO.getBatch()
                    );
                    //解析返回的报文
                    UploadRtMsg uploadRtMsg = UploadFileUtils.explainRetMsg(retMsg);
                    if (uploadRtMsg.isSuccess()) {
                        UpLoadFileVO saveUploadFileVO = getUpLoadFileVO(certUploadRecord, nlsStamInfo, startDate, uploadRtMsg, imgInfo);
                        saveUploadFileVO.setAddFileState("SUCCESS");
                        saveUploadFileVO.setState("SUCCESS");
                        saveUploadFileVO.setBatch(upLoadFileVO.getBatch());
                        upLoadFileService.insertUpLoadFile(saveUploadFileVO);
                        deleteFile(certUploadRecord);
                    }
                    certUploadRecord.setUpSta(uploadRtMsg.isSuccess() ? 1 : 2);
                    certUploadRecord.setUpRetMsg(JSONObject.toJSONString(uploadRtMsg));
                    certUploadRecordDAO.updateByPrimaryKey(certUploadRecord);
                }
            } catch (Exception e) {
                logger.error("上传身份证文件影像平台发生异常，申请信息为：" + JSONObject.toJSONString(certUploadRecord), e);
                certUploadRecord.setUpSta(2);
                certUploadRecord.setUpErrMsg(e.getLocalizedMessage());
                certUploadRecordDAO.updateByPrimaryKey(certUploadRecord);
                continue;
            }
        }
        stopWatch.stop();
        logger.info("身份证上传本次定时任务耗时为：{}", stopWatch.shortSummary());
        return Boolean.TRUE;
    }

    private void deleteFile(CertUploadRecord certUploadRecord) {
        File file = new File(certUploadRecord.getFileUrl());
        if (file.exists()) {
            logger.info("普税贷-开始删除文件：" + file.getAbsolutePath());
            file.delete();
            logger.info("普税贷-删除文件：" + file.getAbsolutePath() + "成功");
        }
        //判断上级目录是否已经为空 如果为空 那么删除
        File dir = new File(FilenameUtils.getFullPath(certUploadRecord.getFileUrl()));
        if (dir.listFiles().length < 1) {
            dir.delete();
        }
    }

    @Override
    public Integer insert(String contFileUrl) {
        logger.info("要保存需要上传到影像平台的文件的路径为：{}", contFileUrl);
        //判断该文件路径在数据库是否已经存在了
        if (certUploadRecordDAO.countByFileUrl(contFileUrl) > 0) {
            return -1;
        }
        CertUploadRecord record = new CertUploadRecord();
        record.setId(UUIDUtil.getUUID());
        record.setCreateTime(new Date());
        record.setUpSta(0);
        record.setUpNum(0);
        record.setFileUrl(contFileUrl);
        record.setPrdId(PsdConstantSet.prdId);
        return certUploadRecordDAO.insert(record);
    }

    /**
     * 获取申请流水信息
     *
     * @param applySeq   流水号
     * @param psdImgInfo 影像信息
     * @return
     */
    private NlsStamInfo getNlsStamInfo(String applySeq, PsdImgInfo psdImgInfo) {
        //获取文件类型 根据类型确定查询的是用信 还是授信记录
        NlsStamInfo result = null;
        if (psdImgInfo.getApplyStage() == 2) {
            //合同文件查询用信记录
            NlsApplyInfoVO param = new NlsApplyInfoVO();
            param.setApplySeq(applySeq);
            NlsApplyInfoVO nlsApplyInfoVO = nlsApplyInfoService.queryByPk(param);
            if (Objects.isNull(nlsApplyInfoVO)) {
                return result;
            }
            result = new NlsStamInfo();
            result.setApplySeq(applySeq);
            result.setCusCertCode(nlsApplyInfoVO.getCertCode());
            result.setChannel(nlsApplyInfoVO.getChannelNo());
            result.setCusCertType(nlsApplyInfoVO.getCertType());
            result.setCusName(nlsApplyInfoVO.getCusName());
            result.setPrdId(nlsApplyInfoVO.getPrdId());
            result.setPrdName(nlsApplyInfoVO.getPrdName());
            result.setTime(nlsApplyInfoVO.getApplyTime());
        } else if (psdImgInfo.getApplyStage() == 1) {
            NlsCreditInfoVO nlsCreditInfoVO = nlsCreditInfoService.queryByLmtApplySeq(applySeq);
            if (Objects.isNull(nlsCreditInfoVO)) {
                return result;
            }
            result = new NlsStamInfo();
            result.setApplySeq(applySeq);
            result.setCusCertCode(nlsCreditInfoVO.getCertCode());
            result.setChannel(nlsCreditInfoVO.getChannelNo());
            result.setCusCertType(nlsCreditInfoVO.getCertType());
            result.setCusName(nlsCreditInfoVO.getCusName());
            result.setPrdId(nlsCreditInfoVO.getPrdId());
            result.setPrdName(nlsCreditInfoVO.getPrdName());
            result.setTime(nlsCreditInfoVO.getCreateTime());
        }
        return result;
    }

    private final PsdImgInfo getImgInfo(String aliasName) {

        if (aliasName.equalsIgnoreCase("certf")) {
            //身份证人像面
            return new PsdImgInfo(ImageBizConstant.IMAGE_TYPE_A01, "certf", "身份证人像面", "0002311", 1);
        }
        if (aliasName.equalsIgnoreCase("certb")) {
            //身份证国徽面
            return new PsdImgInfo(ImageBizConstant.IMAGE_TYPE_A02, "certb", "身份证国徽面", "0002312", 1);
        }
        if (aliasName.equalsIgnoreCase("living")) {
            //活体照
            return new PsdImgInfo(ImageBizConstant.IMAGE_TYPE_A03, "living", "人脸活体识别照片", "0002313", 1);
        }
        if (aliasName.equalsIgnoreCase("sxcont")) {
            //贷款合同
            return new PsdImgInfo(PsdConstantSet.PSD_SX_CONT_TYPE, "sxcont", "个人综合授信合同", "0002322", 1);
        }
        if (aliasName.equalsIgnoreCase("dkcont")) {
            //贷款合同
            return new PsdImgInfo(PsdConstantSet.PSD_YX_CONT_TYPE, "dkcont", "个人借款合同", "0002323", 2);
        }
        if (aliasName.equalsIgnoreCase("sqs")) {
            //授权书
            return new PsdImgInfo(PsdConstantSet.PSD_FILE_TYPE_03, PsdConstantSet.PSD_FILE_TYPE_03, "个人授权书（个人征信和个人信息）", "0002321", 1);
        }
        if (aliasName.equalsIgnoreCase("tmsqs")) {
            //授权书-脱敏版本
            return new PsdImgInfo(PsdConstantSet.PSD_FILE_TM_TYPE_03, "tmsqs", "个人授权书（个人征信和个人信息）", "0002321", 1);
        }
        if (aliasName.equalsIgnoreCase(PsdConstantSet.PSD_FILE_TYPE_04)) {
            //贷款合同
            return new PsdImgInfo(PsdConstantSet.PSD_FILE_TYPE_04, PsdConstantSet.PSD_FILE_TYPE_04, "第三方数据查询授权书", "0002321", 1);
        }
        if (aliasName.equalsIgnoreCase("tmsxcont")) {
            //授信合同-脱敏版本
            return new PsdImgInfo(PsdConstantSet.PSD_SX_CONT_TM_TYPE, "tmsxcont", "个人综合授信合同", "0002322", 1);
        }
        if (aliasName.equalsIgnoreCase("tmdkcont")) {
            //贷款合同
            return new PsdImgInfo(PsdConstantSet.PSD_YX_CONT_TM_TYPE, "tmdkcont", "个人借款合同", "0002323", 2);
        }

        throw new RuntimeException("根据文件名获取文件类型失败，当前文件名中的类型为：" + aliasName);
    }

    /**
     * 将同步过来的身份证正反面数据插入到影像业务详情表
     *
     * @param targetFile 目标文件
     */
    private void insertImageBizDetail(File targetFile) {
        String[] baseNameArr = getBaseNameArr(targetFile);
        final String imgType = getImgInfo(baseNameArr[1]).getImgType();
        ImageBizDetail imageBizDetail = new ImageBizDetail();
        imageBizDetail.setApplySeq(baseNameArr[0]);
        imageBizDetail.setBizStage("身份证文件同步");
        imageBizDetail.setFileDesc("身份证文件同步");
        imageBizDetail.setFileName(targetFile.getName());
        imageBizDetail.setFilePath(targetFile.getAbsolutePath());
        imageBizDetail.setImageId(imgType);
        imageBizDetail.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        imageBizDetail.setImageType(imgType);
        imageBizDetailDao.insertImageBizDetail(imageBizDetail);
    }

    /**
     * 插入数据到影像业务信息
     *
     * @param targetFile 目标文件
     */
    private void insertImageBizInfo(File targetFile) {
        //插入一条日志数据到影像信息表
        String[] baseNameArr = getBaseNameArr(targetFile);
        NlsCreditInfoVO nlsCreditInfoVO = nlsCreditInfoService.queryByLmtApplySeq(baseNameArr[0]);
        if (Objects.isNull(nlsCreditInfoVO)) {
            return;
        }
        ImageBizInfo param = new ImageBizInfo();
        param.setApplySeq(nlsCreditInfoVO.getLmtApplySeq());
        if (!Objects.isNull(imageBizInfoDao.queryByPk(param))) {
            return;
        }
        ImageBizInfo imageBizInfo = new ImageBizInfo();
        imageBizInfo.setApplySeq(baseNameArr[0]);
        imageBizInfo.setCreateDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        imageBizInfo.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        imageBizInfo.setCusId(nlsCreditInfoVO.getCusId());
        imageBizInfo.setCusName(nlsCreditInfoVO.getCusName());
        imageBizInfo.setPrdId(nlsCreditInfoVO.getPrdId());
        imageBizInfo.setPrdCode(nlsCreditInfoVO.getPrdCode());
        imageBizInfo.setPrdName(nlsCreditInfoVO.getPrdName());
        //如下信息先赋空值
        imageBizInfo.setSoltImageAccept("");
        imageBizInfo.setSoltImageCfca("");
        imageBizInfo.setSoltImageThird1("");
        imageBizInfo.setSoltImageThird2("");
        imageBizInfoDao.insertOrUpdateImageBizInfo(imageBizInfo);
    }

    /**
     * 根据信息封装UploadFileVO对象
     *
     * @param certUploadRecord
     * @param nlsStamInfo
     * @param startDate
     * @param uploadRtMsg
     * @return
     */
    private UpLoadFileVO getUpLoadFileVO(CertUploadRecord certUploadRecord, NlsStamInfo nlsStamInfo, String startDate, UploadRtMsg uploadRtMsg, PsdImgInfo psdImgInfo) {
        UpLoadFileVO saveUploadFileVO = new UpLoadFileVO();
        saveUploadFileVO.setApplySeq(nlsStamInfo.getApplySeq());
        saveUploadFileVO.setStartDate(startDate);
        saveUploadFileVO.setImageType(psdImgInfo.getImgType());
        saveUploadFileVO.setBatch(uploadRtMsg.getBatch());
        saveUploadFileVO.setPrdName(StringUtils.isEmpty(nlsStamInfo.getPrdName()) ? "广银普税贷" : nlsStamInfo.getPrdName());
        saveUploadFileVO.setCusName(nlsStamInfo.getCusName());
        saveUploadFileVO.setCertCode(nlsStamInfo.getCusCertCode());
        saveUploadFileVO.setFilePath(certUploadRecord.getFileUrl());
        saveUploadFileVO.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return saveUploadFileVO;
    }

    /**
     * 通过目标文件的文件名进行切割获取信息
     *
     * @param targetFile 目标文件
     * @return
     */
    private String[] getBaseNameArr(File targetFile) {
        return FilenameUtils.getBaseName(targetFile.getName()).split(splitStr);
    }

    /**
     * 关闭流操作
     *
     * @param inputStream      输入流
     * @param fileOutputStream 输出流
     * @throws IOException
     */
    private void closeStream(InputStream inputStream, FileOutputStream fileOutputStream) throws IOException {
        if (fileOutputStream != null) {
            fileOutputStream.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
    }


    /**
     * 获取最大处理数、重试次数
     *
     * @return
     */
    private int[] getHandleNumArr() {
        int[] result = new int[2];
        try {
            SCfgParamVO param = new SCfgParamVO();
            param.setParamKey(PsdConstantSet.MAX_NUM_KEY);
            SCfgParamVO maxNumCfg = sCfgParamService.queryByPk(param);
            if (Objects.isNull(maxNumCfg)) {
                //设置默认值
                result[0] = 50;
            } else {
                result[0] = Integer.parseInt(maxNumCfg.getParamValue());
            }
            param.setParamKey(PsdConstantSet.RETRY_NUM_KEY);
            SCfgParamVO retryNumCfg = sCfgParamService.queryByPk(param);
            if (Objects.isNull(retryNumCfg)) {
                //设置默认值
                result[1] = 3;
            } else {
                result[1] = Integer.parseInt(retryNumCfg.getParamValue());
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return result;
    }
}
